﻿using System;
using System.Linq;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Collections.Generic;
using Microsoft.SharePoint.Administration;
using System.Web.UI.WebControls;

namespace SharePointFarmInfoTimerJob.Layouts.SharePointFarmInfoTimerJob
{
    public partial class SharePointTopologyTimerJob : LayoutsPageBase
    {
        /// <summary>
        /// Web collection list
        /// </summary>
        private List<string> spWebCollectionList = new List<string>();

        #region Events

        /// <summary>
        /// OnInit
        /// </summary>
        /// <param name="e">EventArgs</param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            //Hook the events to the controls
            SPWebCollectionDropDownList.SelectedIndexChanged += new EventHandler(SPWebCollectionList_SelectedIndexChanged);
            SetTimerJobsButton.Click += new EventHandler(SetTimerJobsButton_Click);
            SPSiteList.SelectedIndexChanged += new EventHandler(SPSiteList_SelectedIndexChanged);
        }

        /// <summary>
        /// Page load event
        /// </summary>
        /// <param name="sender">Object</param>
        /// <param name="e">EventArgs</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                //Get the timer job definition which has the matching display name
                List<SPJobDefinition> allJobs = GetTimerJobsByName(Global.jobTitle, true);

                //Get the webcollection and bind it to SPWebCollectionDropDownList
                SPWebCollectionDropDownList.DataSource = spWebCollectionList;
                SPWebCollectionDropDownList.DataBind();

                //Bind SPSite and their site web accordingly
                this.SPSiteBind();
                this.BindSPWeb();

                SPJobDefinition selectedJob = allJobs.FirstOrDefault();

                if (selectedJob != null)
                {
                    //Pre-select the old SPWebApplication
                    this.DropDownListReturnValue(this.SPWebCollectionDropDownList, selectedJob, Global.SPWebApplication);
                    //Bind the SPSite according to the selected SPWebApplication
                    this.SPSiteBind();

                    //Pre-Select the SPSite
                    this.DropDownListReturnValue(this.SPSiteList, selectedJob, Global.SPSiteCollection);
                    //Bind the SPWeb according to the selected SPSite
                    this.BindSPWeb();

                    //Pre-Select the SPWeb
                    this.DropDownListReturnValue(this.SPSiteWebList, selectedJob, Global.SPSiteWebCollection);

                    //Pre-Load the SPList name
                    this.TextBoxReturnValue(this.txtTopoListName, selectedJob, Global.SPList);
                   
                }
            }
        }

        /// <summary>
        /// SPSiteList - Drop down selection changed event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SPSiteList_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Bind the SPSiteWeb according to the selected SPSite
            BindSPWeb();
        }

        /// <summary>
        /// SPWebCollectionList - Dropdown list selection changed event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SPWebCollectionList_SelectedIndexChanged(object sender, EventArgs e)
        {
            SPSiteBind();
            BindSPWeb();
        }

        /// <summary>
        /// Ok button click event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SetTimerJobsButton_Click(object sender, EventArgs e)
        {
            //Job definition collection for the current Web application
            IEnumerable<SPJobDefinition> allJobs = GetTimerJobsByName(Global.jobTitle, true);

            // Update the job for the current Web application.            
            foreach (SPJobDefinition selectedJob in allJobs)
            {
                this.SetValue(this.SPWebCollectionDropDownList, selectedJob, Global.SPWebApplication);
                this.SetValue(this.SPSiteList, selectedJob, Global.SPSiteCollection);
                this.SetValue(this.SPSiteWebList, selectedJob, Global.SPSiteWebCollection);
                selectedJob.Properties[Global.SPList] = this.txtTopoListName.Text;                

                selectedJob.Update();
            }
        } 
        #endregion

        #region Private methods

        /// <summary>
        /// Bind all the site web to SPSiteWebList
        /// </summary>
        private void BindSPWeb()
        {
            //Clear the list item
            this.SPSiteWebList.Items.Clear();

            if (this.SPSiteList.SelectedItem == null)
            {
                return;
            }

            //Get the SiteWeb based on selected site
            using (SPSite site = new SPSite(this.SPSiteList.SelectedItem.Text))
            {
                SPWebCollection siteWebCollection = site.AllWebs;

                if (siteWebCollection.Count > 0)
                {
                    List<string> webCollection = new List<string>();

                    //Update the site web source
                    foreach (SPWeb web in siteWebCollection)
                    {
                        webCollection.Add(web.Url);
                    }

                    //Bind the source data
                    this.SPSiteWebList.DataSource = webCollection;
                    this.SPSiteWebList.DataBind();
                }
            }
        }

        private void SPSiteBind()
        {
            //Clear the items
            this.SPSiteList.Items.Clear();

            SPSiteCollection currentSPSiteCollection = SPWebApplication.Lookup(new Uri(SPWebCollectionDropDownList.SelectedValue)).Sites;

            if (currentSPSiteCollection.Count > 0)
            {
                List<string> siteCollection = new List<string>();

                //Update the site source
                foreach (SPSite site in currentSPSiteCollection)
                {
                    siteCollection.Add(site.Url);
                }

                //Bind the source data
                this.SPSiteList.DataSource = siteCollection;
                this.SPSiteList.DataBind();
            }
        }

        private void SetValue(DropDownList source, SPJobDefinition selectedJob, string propertyValue)
        {
            if (source.Items.Count <= 0)
            {
                return;
            }

            selectedJob.Properties[propertyValue] = source.SelectedValue;
        }

        /// <summary>
        /// Pre load the textbox with the given property value from its job definition
        /// </summary>
        /// <param name="source">Textbox input</param>
        /// <param name="selectedJob">SharePoint Job definition</param>
        /// <param name="propertyValue">Property kay name</param>
        private void TextBoxReturnValue(TextBox source, SPJobDefinition selectedJob, string propertyValue)
        {
            if (!selectedJob.Properties.Contains(propertyValue))
            {
                return;
            }

            string value = selectedJob.Properties[propertyValue].ToString();

            if (String.IsNullOrEmpty(value))
            {
                return;
            }

            source.Text = value;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <param name="selectedJob"></param>
        /// <param name="propertyValue"></param>
        private void DropDownListReturnValue(DropDownList source, SPJobDefinition selectedJob, string propertyValue)
        {
            if (!selectedJob.Properties.Contains(propertyValue))
            {
                return;
            }

            string value = selectedJob.Properties[propertyValue].ToString();

            if (String.IsNullOrEmpty(value))
            {
                return;
            }

            this.SelectItem(source, value);
        }

        private void SelectItem(DropDownList source, string selectedItem)
        {
            source.ClearSelection();

            if (source.Items.FindByValue(selectedItem) != null)
            {
                source.Items.FindByValue(selectedItem).Selected = true;
            }
        }

        /// <summary>
        /// Get the jobdefinition based on the name. 
        /// Updates the Webapplication list based on the collectWebApplication (bool) value
        /// </summary>
        /// <param name="displayName">string</param>
        /// <param name="collectWebApplication">bool</param>
        /// <returns></returns>
        private List<SPJobDefinition> GetTimerJobsByName(string displayName, bool collectWebApplication)
        {
            List<SPJobDefinition> AllJobs = new List<SPJobDefinition>();

            SPFarm farm = SPFarm.Local;

            //For all Servers in the Farm (could be different)
            foreach (SPServer server in farm.Servers)
            {
                //Each Service Instance on the Server
                foreach (SPServiceInstance svc in server.ServiceInstances)
                {
                    if (svc.Service.JobDefinitions.Count > 0)
                    {
                        //If its a Web Service, must get the WebApp from the Web Service Entity
                        if (svc.Service is SPWebService)
                        {
                            SPWebService websvc = (SPWebService)svc.Service;
                            AllJobs.AddRange(from webapp in websvc.WebApplications
                                             from def in webapp.JobDefinitions
                                             where def.DisplayName.ToLower() == displayName.ToLower()
                                             select def);

                            if (collectWebApplication)
                            {
                                foreach (SPWebApplication webApp in websvc.WebApplications)
                                {
                                    //Update the webapplication source
                                    spWebCollectionList.Add(webApp.GetResponseUri(SPUrlZone.Default).AbsoluteUri);
                                }
                            }
                        }
                        else
                        {
                            //Otherwise Get it directly from the Service
                            AllJobs.AddRange(svc.Service.JobDefinitions.Where(def => def.DisplayName.ToLower() == displayName.ToLower()));
                        }
                    }
                }
            }

            return AllJobs;
        } 
        #endregion       
    }
}


